home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
130 MIDI Tool Box
/
130 MIDI Tool Box.iso
/
ptmid
/
ptmid.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-01-08
|
12KB
|
410 lines
/*
* ptmid.c: Creates Protracker MODule files from MIDI files.
* (My first attempt at Hungarian Notation.. wince!)
*
* Author: Andrew Scott (c)opyright 1994
*
* Date: 17/11/1993 ver 0.0
* 8/1/1994 ver 0.1
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <io.h>
#include "ptmid.h"
char bDrumch = 9, szId[5] = "M.K.";
int fNocopy = 0, fQuiet = 0, fExtend = 0;
int wPatmax = 64, wPtchan = 4, wQuantval = 16;
SI *rgpsiDrum[128], **rgppsiIns[129], *psiTree = NULL;
Sz szTitle = "Converted by PTMID!", szQuant = NULL;
/*
* Init: Does all those initialization things (which aren't too involved).
*/
static void Init()
{
int i;
rgppsiIns[128] = NULL; /** Make sure sample-info arrays are clear **/
for (i = 128; i--; ) {
rgpsiDrum[i] = NULL;
rgppsiIns[i] = NULL;
}
}
/*
* BuildFn: Builds a full filename given a string which is the old filename,
* and a default extension to use if one is not present in the string. After
* building the new filename, any extension in the old name is removed.
*/
void BuildFn(Fn fnNew, Sz fnOld, Sz fnExt)
{
Sz fnT = fnNew;
int fExt = 0;
while (*fnOld) {
if ('.' == (*(fnT++) = *fnOld)) { /** Copy a char, test for extension **/
fExt = 1;
*fnOld = 0; /** yes.. note extension exists and remove it **/
}
fnOld++;
}
if (!fExt) { /** If no extension found **/
*(fnT++) = '.';
while ((*(fnT++) = *(fnExt++))); /** copy the default one - fnExt **/
} else
*fnT = 0;
}
/*
* SzReadPfile: Reads the next string from the textfile given and returns it.
* If file is at end, returns NULL.
*/
Sz SzReadPfile(FILE *pfileText)
{
int ch, cch = 0, cchMac = 80;
Sz szT, szStart;
if (feof(pfileText))
return NULL;
szStart = szT = (Sz) malloc(80); /** Set aside 80 characters for line **/
while ((ch = getc(pfileText)) != EOF && ch != '\n') {
*szT = ch;
if (++cch == cchMac) { /** If that's not enough **/
cchMac += 40;
szStart = (Sz) realloc(szStart, cchMac); /** increase in steps of 40 **/
szT = szStart + cch;
} else
szT++;
}
*szT = 0;
return (Sz) realloc(szStart, cch + 1);
}
/*
* PsiAddsample: Given a sample's filename, will look it up in the tree
* and return a pointer to it if it exists, else will create it and return
* a pointer to the newly created entry.
*/
SI *PsiAddsample(Sz fnSample)
{
SI *psiT;
if (NULL == psiTree) { /** If nothing in tree **/
psiT = psiTree = (SI *) malloc(sizeof(SI)); /** create root node **/
psiT->fnSample = strdup(fnSample);
psiT->pitch = -1;
psiT->sample = -1;
psiT->psiL = psiT->psiR = NULL;
} else { /** Else **/
SI *psiOld;
int cmp;
psiT = psiTree;
while (psiT != NULL) { /** find spot for sample in tree **/
psiOld = psiT;
cmp = strcmp(psiT->fnSample, fnSample);
if (!cmp)
break;
else if (0 > cmp)
psiT = psiT->psiL;
else
psiT = psiT->psiR;
}
if (NULL == psiT) {
psiT = (SI *) malloc(sizeof(SI)); /** and create entry **/
if (0 > cmp)
psiOld->psiL = psiT;
else
psiOld->psiR = psiT;
psiT->fnSample = strdup(fnSample);
psiT->pitch = -1;
psiT->sample = -1;
psiT->psiL = psiT->psiR = NULL;
}
}
return psiT;
}
/*
* PsiPrunePsi: Returns the given sample tree, but without any redundant
* samples. Any redundant samples are freed. If no samples remain, NULL
* is returned.
*/
SI *PsiPrunePsi(SI *psi)
{
if (NULL == psi)
return NULL;
psi->psiL = PsiPrunePsi(psi->psiL); /** Prune left and right branches **/
psi->psiR = PsiPrunePsi(psi->psiR);
if (-1 == psi->pitch) { /** If root of tree redundant, need to remove it **/
SI *psiT;
if (NULL == psi->psiL) { /** If no left branch **/
psiT = psi->psiR;
free(psi); /** replace root **/
psi = psiT; /** with right branch **/
} else if (NULL == psi->psiR) { /** If no right branch **/
psiT = psi->psiL;
free(psi); /** replace root **/
psi = psiT; /** with left branch **/
} else if (NULL == psi->psiL->psiR) { /** If left branch has no right **/
psiT = psi->psiL;
psiT->psiR = psi->psiR; /** put right branch on right of left **/
free(psi); /** and replace root **/
psi = psiT; /** with left branch **/
} else { /** Else.. there's 2 full branches - yuck! **/
SI *psiOld;
psiT = psi->psiL;
while (NULL != psiT->psiR) { /** Find rightmost entry on left branch **/
psiOld = psiT;
psiT = psiT->psiR;
}
psiOld->psiR = psiT->psiL;
psiT->psiL = psi->psiL;
psiT->psiR = psi->psiR;
free(psi); /** remove root **/
psi = psiT; /** and replace it with that entry **/
}
}
return psi;
}
/*
* ReadconfigFn: Given the filename of the configuration file, it interprets
* each line and sets up options and sample-tables.
*/
void ReadconfigFn(Sz fnConfig)
{
FILE *pfileConfig;
Sz szLine, szTok;
int csz = 0, fError = 0;
if (NULL == (pfileConfig = fopen(fnConfig, "rt"))) {
fprintf(stderr, "ptmid: Cannot find config file: %s\n", fnConfig);
exit(1);
}
while ((szLine = SzReadPfile(pfileConfig)) != NULL) { /** With every line.. **/
csz++;
if ('#' != szLine[0] && NULL != (szTok = strtok(szLine, " \t")))
if ('0' <= szTok[0] && '9' >= szTok[0] || !strcmp(szTok, "def")) {
int irgppsi, cpsi; /** If an instrument definition **/
SI **ppsi;
if ('d' == szTok[0])
irgppsi = 128;
else
irgppsi = atoi(szTok); /** decode instrument **/
if (irgppsi < 129)
while (NULL != (szTok = strtok(NULL, " \t"))) { /*** With every sample.. ***/
if (NULL == rgppsiIns[irgppsi]) /*** Ensure allocated ***/
rgppsiIns[irgppsi] = ppsi = (SI **) malloc(sizeof(SI *) * 2);
else {
ppsi = rgppsiIns[irgppsi];
for (cpsi = 2; NULL != *ppsi; cpsi++, ppsi++);
rgppsiIns[irgppsi] = ppsi = (SI **) realloc(rgppsiIns[irgppsi],
sizeof(SI *) * cpsi);
ppsi += cpsi - 2;
}
ppsi[0] = PsiAddsample(szTok); /*** Put sample in array ***/
ppsi[1] = NULL;
}
else
fError = 1;
} else if ('d' == szTok[0] && '0' <= szTok[1] && '9' >= szTok[1]) {
int irgpsi; /** If a percussion definition **/
if ((irgpsi = atoi(szTok + 1)) < 128 && /** decode instrument **/
(szTok = strtok(NULL, " \t")) != NULL) {
if (NULL != rgpsiDrum[irgpsi])
free(rgpsiDrum[irgpsi]); /** and free up if previously used **/
rgpsiDrum[irgpsi] = PsiAddsample(szTok); /** Put sample in array **/
} else
fError = 1;
} else if (!strcmp(szTok, "sample")) { /** If sample info **/
Sz fnSample;
SI *psi;
int irgb;
static int rgbPitch[7] = {45, 47, 36, 38, 40, 41, 43};
if ((fnSample = strtok(NULL, " \t")) == NULL) /** Get name **/
fError = 1;
else if ((szTok = strtok(NULL, " \t")) == NULL)
fError = 1;
else if ((irgb = toupper(szTok[0]) - 'A') < 0 || 6 < irgb) /** Get pitch **/
fError = 1;
else {
psi = PsiAddsample(fnSample); /** Make sure sample allocated **/
if ('#' == szTok[1])
szTok++;
psi->pitch = rgbPitch[irgb] + 12 * atoi(szTok + 1) +
('#' == szTok[0] ? 1 : 0);
if ((szTok = strtok(NULL, " \t")) == NULL)
psi->wLppos = 0;
else
psi->wLppos = atoi(szTok); /** Get loop start **/
if ((szTok = strtok(NULL, " \t")) == NULL)
psi->wLplen = 0;
else
psi->wLplen = atoi(szTok); /** Get loop length **/
}
} else if (!strcmp(szTok, "formid")) /** If module-id **/
if ((szTok = strtok(NULL, " \t")) == NULL)
fError = 1;
else
strncpy(szId, szTok, 4); /** store it **/
else if (!strcmp(szTok, "patmax")) /** If max. patterns **/
if ((szTok = strtok(NULL, " \t")) == NULL)
fError = 1;
else {
int wT;
if ((wT = atoi(szTok)) != 0 && 128 >= wT)
wPatmax = wT; /** store them **/
else
fError = 1;
}
else if (!strcmp(szTok, "ptchan")) /** If max. channels **/
if ((szTok = strtok(NULL, " \t")) == NULL)
fError = 1;
else {
int wT;
if ((wT = atoi(szTok)) != 0 && MAXPTCHAN >= wT)
wPtchan = wT; /** store them **/
else
fError = 1;
}
else if (!strcmp(szTok, "drumch")) /** If MIDI percussion channel **/
if ((szTok = strtok(NULL, " \t")) == NULL)
fError = 1;
else {
int bT;
if ((bT = atoi(szTok)) != 0)
bDrumch = bT - 1; /** store it **/
}
else if (!strcmp(szTok, "fract") && NULL == szQuant) { /** If quantize frac. **/
int wT;
if ((szQuant = strtok(NULL, " \t")) == NULL ||
!(wT = ValidquantSz(strlwr(szQuant)))) /** decode **/
fError = 1;
else
wQuantval = wT; /** and store it **/
} else if (!strcmp(szTok, "extend")) /** If extend-notes flag **/
fExtend = 1; /** toggle **/
else if (!strcmp(szTok, "nocopy")) /** If no-copyright flag **/
fNocopy = 1; /** toggle **/
else
fError = 1;
if (fError) { /** If an error at any point, reveal line **/
fprintf(stderr, "ptmid: Error in config file: line %d\n", csz);
exit(1); /** and quit **/
}
free(szLine);
}
if (NULL == rgppsiIns[128]) {
fprintf(stderr, "ptmid: No default instrument defined in config file\n");
exit(1);
}
if ((psiTree = PsiPrunePsi(psiTree)) == NULL) {
fprintf(stderr, "ptmid: No sample definitions found in config file\n");
exit(1);
}
}
/*
* main: Parses arguments to program and opens appropriate MOD and MID files.
*/
int main(int argc, char **argv)
{
int cNames = 0;
Sz fnDef, fnConfig = DEFCONFIG;
Fn fnIn, fnOut;
FILE *pfileMod;
Tune *ptuneMusic;
Init();
for (argv++; NULL != *argv; argv++) /** Run through all parameters **/
if ('-' == **argv) /** If parameter is a switch **/
switch ((*argv)[1]) { /** check what sort **/
case 'c':
if ((*argv)[2])
fnConfig = *argv + 2; /** c: set config file **/
break;
case 'd':
bDrumch = atoi(*argv + 2) - 1; /** d: set drum channel **/
break;
case 'f': {
int wT; /** f: set quantize fraction **/
if ((wT = ValidquantSz(strlwr(*argv + 2))))
wQuantval = wT;
else
fprintf(stderr, "ptmid: Invalid quantize fraction - using default\n");
break;
}
case 'q':
fQuiet = !fQuiet; /** q: toggle quiet mode **/
break;
}
else { /** Else must be a filename **/
if (0 == cNames)
BuildFn(fnIn, fnDef = *argv, "mid");
else if (1 == cNames)
BuildFn(fnOut, *argv, "mod");
cNames++;
}
if (1 > cNames || 2 < cNames) { /** If no filenames - error **/
printf("Use: ptmid [-cFile] [-dChannel] [-fFrac] [-q] infile[.mid] [outfile[.mod]]\n");
printf(" version " PTVER "\n");
printf(" Creates Protracker MOD files from General MIDI files\n");
exit(1);
} else if (1 == cNames) /** If one filename **/
BuildFn(fnOut, fnDef, "mod"); /** build other one **/
if (!fQuiet)
printf("ptmid ver " PTVER ": Converting '%s' to '%s'\n", fnIn, fnOut);
ReadconfigFn(fnConfig);
if (access(fnIn, 1)) {
fprintf(stderr, "ptmid: Cannot access file: %s\n", fnIn);
exit(1);
}
if ((ptuneMusic = PtuneLoadFn(fnIn)) == NULL) {
fprintf(stderr, "ptmid: Not a legal MIDI file: %s\n", fnIn);
exit(1);
}
if (!fQuiet)
printf("Analyzing..\n");
ResolvePtune(ptuneMusic);
if (!fQuiet)
printf("Writing..\n");
if ((pfileMod = fopen(fnOut, "wb")) == NULL) {
fprintf(stderr, "ptmid: Cannot create file: %s\n", fnOut);
exit(1);
}
SavePtunePfile(ptuneMusic, pfileMod);
fclose(pfileMod);
if (!fQuiet)
printf("Done.\n");
}